<?php
/**
 * SocialEngine
 *
 * @category   Application_Core
 * @package    Core
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 * @version    $Id: Settings.php 8393 2011-02-04 01:03:15Z john $
 * @author     John
 */

/**
 * @category   Application_Core
 * @package    Core
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 */
class Core_Model_DbTable_Settings extends Engine_Db_Table
{
  // General
  
  /**
   * @var Zend_Cache_Core
   */
  protected $_cache;

  protected $_settings;
  
  public function init()
  {
    // Get cache
    $this->_cache = Zend_Registry::get('Zend_Cache');

    // Load settings
    $this->_loadSettings();
  }

  public function reloadSettings()
  {
    $this->_cache->remove('settings');
    $this->_settings = null;
    $this->_loadSettings();
  }



  // Magic
  
  public function __get($key)
  {
    return $this->getSetting($key);
  }

  public function __set($key, $value)
  {
    return $this->setSetting($key, $value);
  }

  public function __isset($key)
  {
    return $this->hasSetting($key);
  }

  public function __unset($key)
  {
    return $this->removeSetting($key);
  }



  // Accessors
  
  public function getSetting($key, $default = null)
  {
    $key = $this->_normalizeMagicProperty($key);
    $path = explode('.', $key);
    $final = array_pop($path);
    
    $current =& $this->_settings;
    if( !empty($path) ) {
      foreach( $path as $pathElement ) {
        if( !isset($current[$pathElement]) || !is_array($current[$pathElement]) ) {
          return $default;
        }
        $current =& $current[$pathElement];
      }
    }

    if( isset($current[$final]) ) {
      return $current[$final];
    } else {
      return $default;
    }
  }
  
  public function hasSetting($key)
  {
    return ( null !== $this->getSetting($key) );
  }

  public function setSetting($key, $value)
  {
    $key = $this->_normalizeMagicProperty($key);

    // Array mode
    if( is_array($value) ) {
      foreach( $value as $k => $v ) {
        $this->setSetting($key . '.' . $k, $v);
      }
    }

    // Scalar mode
    else {
      $path = explode('.', $key);
      $final = array_pop($path);

      $current =& $this->_settings;
      if( !empty($path) ) {
        foreach( $path as $pathElement ) {
          if( !isset($current[$pathElement]) || !is_array($current[$pathElement]) ) {
            $current[$pathElement] = array();
          }
          $current =& $current[$pathElement];
        }
      }

      // Delete
      if( isset($current[$final]) && null === $value ) {
        $this->delete(array(
          'name = ?' => $key,
        ));
        $this->delete(array(
          'name LIKE ?' => $key . '.%',
        ));
        unset($current[$final]);
      }
      // Update
      else if( isset($current[$final]) ) {
        // Only if not the same?
        if( $current[$final] !== $value ) {
          $this->update(array(
            'value' => $value,
          ), array(
            'name = ?' => $key,
          ));
        }
        // Reselect?
        $current[$final] = $this->find($key)->current()->value;
      }
      // Insert
      else {
        $this->insert(array(
          'name' => $key,
          'value' => $value,
        ));
        // Reselect?
        $current[$final] = $this->find($key)->current()->value;
      }

      // Flush the cache
      $this->_cache->remove('settings');
    }
    
    return $this;
  }

  public function removeSetting($key)
  {
    return $this->setSetting($key, null);
  }



  // Flat Accessors

  public function getFlatSetting($key, $default = null, $flatChar = '_')
  {
    $value = $this->getSetting($key, $default);
    if( is_array($value) ) {
      $this->_flattenArray($value, $flatChar);
    }
    return $value;
  }

  public function setFlatSetting($key, $value, $flatChar = '_')
  {
    $newValue = array();
    foreach( $value as $k => $v ) {
      $this->_expandArray(explode($flatChar, $k), $v, $newValue);
    }
    $this->setSetting($key, $newValue);
  }



  // Utility

  protected function _loadSettings()
  {
    // Try to load from cache
    $data = $this->_cache->load('settings');
    if( $data && is_array($data) ) {
      $this->_settings = $data;
      return;
    }

    // Load from db
    $rows = $this->select()
      ->from($this, array('name', 'value'))
      ->query()
      ->fetchAll(Zend_Db::FETCH_NUM);

    $data = array();
    foreach( $rows as $row ) {
      $this->_expandArray(explode('.', $row[0]), $row[1], $data);
    }
    $this->_settings = $data;

    $this->_saveSettings();
  }
  
  protected function _saveSettings()
  {
    // Try to save to cache
    $this->_cache->save($this->_settings, 'settings');
  }

  protected function _normalizeMagicProperty($key)
  {
    return /*strtolower(*/str_replace('_', '.', $key)/*)*/;
  }

  protected function _expandArray(array $path, $value, array &$array)
  {
    $current =& $array;
    foreach( $path as $pathElement ) {
      if( !isset($current[$pathElement]) || !is_array($current[$pathElement]) ) {
        $current[$pathElement] = array();
      }
      $current =& $current[$pathElement];
    }
    $current = $value;
  }

  protected function _flattenArray(&$array, $char = '_')
  {
    do {
      $break = true;
      foreach( $array as $key => $value ) {
        if( is_array($value) ) {
          foreach( $value as $subkey => $subvalue ) {
            $newKey = $key . $char . $subkey;
            $array[$newKey] = $subvalue;
          }
          unset($array[$key]);
          $break = false;
        }
      }
    } while( !$break );
  }
}